<?php

require_once ('ClassGenerator.php');
/**
 * Class for generating the javascript code for the MySQL classes
 *
 */
class ClassGeneratorJavascript extends ClassGenerator {

	/**
	 *
	 *@param string $class_name The name of the class to generate
	 *@param array $fields The table structure from which to generate a class
	 *@param array $foreign_tables The set of tables for which this class's primary key is a foreign key
	 *@param bool $ignore_class_name_reformatting Instructs formatClassName to ignore reformatting, useful for non-english databases 
	 */
	function __construct($database, $table_name, $fields, $foreign_tables, $ignore_class_name_reformatting = false) {
		parent::__construct ( $database, $table_name, $fields, $foreign_tables, $ignore_class_name_reformatting );

	}

	function generateClassCode() {
		//TODO: getters for foreign classes
		//TODO: insert, delete calls


		//header
		$header = "

/**
* Prototype functions for $this->class_name
*/
" . $this->class_name . ".prototype = {
";

		$public_fields = "";
		//loop through each of the fields
		foreach ( $this->fields as $field_name => $field_properties ) {
			//get the php data type
			$data_type = ConvertMySQLTypeNameToPHPTypeName ( $field_properties [DATA_TYPE_FIELD] );
				
			//check if this is the primary field
			$is_primary_field = false;
			if ($field_properties [INDEX_FIELD] == PRIMARY_FIELD) {
				$primary_key_field = $field_name;
				$primary_key_type = $field_properties [DATA_TYPE_FIELD];
				$is_primary_field = true;
			}
				
			//create the code for this field: variables, getters, setters
			$public_fields .= $this->generateFieldCode ( $data_type, $field_name, $is_primary_field );
		}
		$constructor = "";
		if (isset ( $primary_key_field )) {
			$constructor = $this->generateConstructor ( $primary_key_field, $primary_key_type );
		}

		$foreign_class_getters = ""; //TODO: $this->generateForeignClassGetters ( $primary_key_field );

		$deleteMeFunction = "
	/**
	* Deletes this object from the database
	* @return The primary key value for this object
	*/
	deleteMeFromDatabase: function (callback_function){
		var parameters = new Object();
		this.call_web_service('deleteMeFromDatabase', parameters, function(result){
			if(typeof(callback_function) == 'function')
				callback_function(result);
		});
	},";

		$footer = "
};";

		$web_service_functions = "
	/**
	* Used for calling the web service
	*/
	call_web_service: function(method, parameters, callback_function){
		parameters.model = '$this->class_name';
		parameters.method = method;
		parameters.primary_key_value = this.primary_key_value;
		parameters.encoding = 'json';
		$.ajax( {
			url : '" . $this->database . "_mvc/View/web_service.php',
			type : 'GET',
			dataType : 'json',
			data : parameters,
			error : errorFunction,
			success : function(result) {
				if(typeof(callback_function) == 'function'){
					callback_function(result);
				}
			}
		});	
	},
	
	call_web_service_post: function(method, parameters, callback_function){
		parameters.model = '$this->class_name';
		parameters.method = method;
		parameters.primary_key_value = this.primary_key_value;
		parameters.encoding = 'json';
		$.ajax( {
			url : '" . $this->database . "_mvc/View/web_service.php',
			type : 'POST',
			dataType : 'json',
			data : parameters,
			error : errorFunction,
			success : function(result) {
				if(typeof(callback_function) == 'function'){
					callback_function(result);
				}
			}
		});
	}
";
		return $constructor . $header . $deleteMeFunction . $public_fields . $foreign_class_getters . $web_service_functions . $footer;
	}

	function generateConstructor($primary_key_field, $primary_key_type) {
		//TODO: change this to being passed a properties object that has all it's fields
		$constructor = "
/**
* Javascript DB Access class generated by Brent Rossen's MySQL Ajax Database Access Layer
* This class is for reference only. In practice, you should load all the javascript classes once using
* " . $this->database . "_mvc/Model/" . $this->database . "_javascript_classes.min.js, which is a combined and minified
* version of all the javascript classes in the " . $this->database . " MVC framework.
* @author Brent Rossen
* @constructor constructor for $this->class_name object by_$primary_key_field
* @param $primary_key_type $primary_key_field
*/
function $this->class_name(properties){	
	this.$primary_key_field = properties.$primary_key_field;
	this.primary_key_value = properties.$primary_key_field;
	for (var prop in properties)
	{
		this[prop] = properties[prop]; 
	}
//	if(initializeSynchronous){
//		var parameters = new Object;
//		parameters.model = '$this->class_name';
//		parameters.method = 'constructFrom_$primary_key_field';
//		parameters.primary_key_value = $primary_key_field;
//		parameters.$primary_key_field = $primary_key_field;
//		parameters.encoding = 'json';
//		var jsonobj = $.ajax( {
//			url : '" . $this->database . "_mvc/View/web_service.php',
//			type : 'GET',
//			dataType : 'json',
//			data : parameters,
//			async: false
//		}).responseText;
//		alert(jsonobj);
//		//set each of the variables
//		for (var i in this) {
//			if(jsonobj[this[i].name] != 'undefined'){
//				alert(this[i].name + ' = ' + jsonobj[this[i].name]);
//				this[i] = jsonobj[this[i].name];
//			}
//		}			
//	}
};

";
		$class_properties = getClassProperties($this->class_name);
		$class_prop_array = explode(", ", $class_properties);
		$parameters_string = "";
		foreach($class_prop_array as $prop){
			if($prop != "")
			$parameters_string .= "	parameters.$prop = $prop;
";
		}
		$insertionFunction = "";
		if($class_properties != ""){
			$insertionFunction = "
/**
* Static function to insert a new $this->class_name into the database
* Submit empty string for any variables you want set to null or the default value
*/
function insertNew$this->class_name(".$class_properties.", callback_function){
	//check if the number of arguments given is equal to the number of arguments expected
	if(arguments.length != insertNew$this->class_name.length){
		alert('MADAL ERROR: number of arguments passed ('+arguments.length+') to insertNew$this->class_name, is not equal to the expected number ('+insertNew$this->class_name.length+'). Call aborted.');
		return;
	}
	
	var parameters = new Object();
			$parameters_string
	parameters.model = '$this->class_name';
	parameters.method = 'insertNew$this->class_name';
	parameters.encoding = 'json';
	$.ajax( {
		url : '" . $this->database . "_mvc/View/web_service.php',
		type : 'GET',
		dataType : 'json',
		data : parameters,
		success : function(result) {
			if(typeof(callback_function) == 'function'){
				callback_function(result);
			}
		}
	});
};
";
		}
		return $constructor . $insertionFunction;
	}

	/**
	 * Generates a javascript class's field code
	 * @param string $field_type
	 * @param string $field_name
	 * @param string $parameter_value
	 * @return string the code for the parameter
	 */
	function generateFieldCode($field_type, $field_name, $is_primary_field) {
		$field_declaration = "
	
	/**
	* You should not get this value directly or assign to it directly.
	* use get_$field_name and set_$field_name
	* @var $field_type
	*/
	$field_name: 'undefined',";
	$getter = "
	/**
	 * Gets $field_name
	 * If $field_name has been initialized via a previous call, $field_name will be returned immediately to the callback_function.
	 * @param function callback_function The function to call on asynchronous return
	 * @return $field_type
	 */
	get_$field_name: function (callback_function){
		if(this.$field_name != 'undefined'){
			callback_function(this.$field_name);
		} else {
			var parameters = new Object();
			this.call_web_service('get_$field_name', parameters, function(result){
				this.$field_name = result;
				if(typeof(callback_function) == 'function')
					callback_function(result);
			});
		}
	},";
	if (! $is_primary_field) {
		
		//TODO: inherit this call from a parent, or make it a global method
		$setter = "
	/**
	 * Sets $field_name to the specified value including updating the database.
	 * Preserves optimistic concurrency.
	 * If $field_name is still 'undefined', this method calls the database to retrieve field name, and then sets it.
	 * Assumes successful and sets the local variable. It's up to you to check if it was actually successful and refresh the page if it was not.
	 * Failure means that the local page is out of sync with the database.
	 * @param $field_type $field_name
	 * @return string 'true' on success, error message on failure
	 */
	set_$field_name: function ($field_name, callback_function){
		if(this.$field_name != 'undefined'){
			var parameters = new Object;
			parameters.previous_$field_name = this.$field_name;
			parameters.new_$field_name = $field_name;
			this.$field_name = $field_name;";
		if($field_type == "TextArea"){
			$setter .= "
			this.call_web_service_post('set_$field_name', parameters, function(result) {";
		}
		else{
			$setter .= "
			this.call_web_service('set_$field_name', parameters, function(result) {";
		}
		$setter .= "
					if(typeof(callback_function) == 'function')
						callback_function(result);
				}
			);	
		} else {
			var parameters = new Object();
			this.call_web_service('get_$field_name', parameters, function(){
				set_$field_name($field_name, callback_function);
			});
		}		
	},";
	} else {
		$setter = "
	primary_key_field_name: '$field_name',
	primary_key_value: 'undefined',
	";

	}

	return $field_declaration . $getter . $setter;
	}

}

?>